package cz.matasek.dbLogger.sql;

/**
 * Enumeration of the SQL data types.
 * Every data type has a token saying if the data type is recommended to be
 * logged. The reason is that logs are saved in XML and therefore data types
 * have to be:
 * <ul>
 *  <li>convertable into string,</li>
 *  <li>its string representation should not be quite long.</li>
 * </ul>
 *
 * @author Luboš Matásek
 */
public enum SQLDataType {

    /**
     * Bigint.
     */
    BIGINT(true),
    /**
     * Boolean.
     */
    BOOLEAN(true),
    /**
     * Char.
     */
    CHAR(true),
    /**
     * Character.
     */
    CHARACTER(true),
    /**
     * Character varying.
     */
    CHARACTER_VARYING(true),
    /**
     * Date.
     */
    DATE(true),
    /**
     * Integer.
     */
    INTEGER(true),
    /**
     * Number.
     */
    NUMBER(true),
    /**
     * Smallint.
     */
    SMALLINT(true),
    /**
     * Text.
     */
    TEXT(false),
    /**
     * Timestamp.
     */
    TIMESTAMP(true),
    /**
     * Timestamp without time zone.
     */
    TIMESTAMP_WITHOUT_TIME_ZONE(true),
    /**
     * Unknown data type.
     */
    UNKNOWN(false),
    /**
     * Varchar2.
     */
    VARCHAR2(true),
    /**
     * XML.
     */
    XML(false),
    /**
     * XMLType.
     */
    XMLTYPE(false);
    /**
     * <code>true</true> if this SQL data type is recommended to be logged;
     * <code>false</code> otherwise.
     */
    private boolean isLoggable;

    /**
     * Creates a new <code>SQLDataType</code> object.
     *
     * @param isLoggable <code>true</code> if this SQL data type is recommended
     * to be logged; <code>false</code> otherwise
     */
    private SQLDataType(boolean isLoggable) {
        this.isLoggable = isLoggable;
    }

    /**
     * Returns SQL data type of the specified name.
     * If data type of the specified name does not exist, unknown data type
     * is returned.
     *
     * @param name name of the SQL data type
     * @return SQL data type
     */
    public static SQLDataType getType(String name) {
        SQLDataType dataType;
        try {
            // either data type exists (the name is converted to upper case,
            // spaces are replaced with underscore and text in brackets is
            // omitted
            dataType = SQLDataType.valueOf(
                    name.toUpperCase().replaceAll(" ", "_").replaceAll("\\(.*\\)", ""));
        } catch (IllegalArgumentException ex) {
            // or data type is treated unknown
            dataType = SQLDataType.UNKNOWN;
        }

        // sends the result
        return dataType;
    }

    /**
     * Returns name of the SQL data type.
     *
     * @return string representation of the SQL data type
     */
    @Override
    public String toString() {
        // the name is converted into lower case and underscores are replaced
        // with spaces
        return name().toLowerCase().replaceAll("_", " ");
    }

    /**
     * Returns whether this column type is recommended to be logged.
     *
     * @return <code>true</code> if this data type is recommeneded to be logged;
     * <code>false</code> otherwise
     */
    public boolean isLoggeable() {
        return isLoggable;
    }
}
